/**
 * Copyright (c) 2008, Andrew Carter
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer. Redistributions in binary form must reproduce 
 * the above copyright notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the distribution. Neither the 
 * name of Andrew Carter nor the names of contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.acarter.scenemonitor.propertydescriptor.definitions.renderstate;

import com.acarter.propertytable.Property;
import com.acarter.propertytable.PropertySection;
import com.acarter.propertytable.PropertySectionState;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject;
import com.acarter.propertytable.propertyobject.FloatPropertyObject;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject.I_BooleanPropertyObjectListener;
import com.acarter.propertytable.propertyobject.FloatPropertyObject.I_FloatPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.ColorRGBAPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.Vector3fPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.ColorRGBAPropertyObject.I_ColorRGBAPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.Vector3fPropertyObject.I_Vector3fPropertyObjectListener;
import com.jme.light.DirectionalLight;
import com.jme.light.Light;
import com.jme.light.PointLight;
import com.jme.light.SpotLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.state.LightState;
import com.jme.scene.state.RenderState;

/**
 * @author Carter
 * 
 */
public class LightStatePropertyPage extends RenderStatePropertyPage {

    /**
     * 
     */
    public LightStatePropertyPage() {

	PropertySection section = new PropertySection("Light State");
	section.addProperty(new Property("Global Ambient", new ColorRGBAPropertyObject()));
	section.addProperty(new Property("Local Viewer", new BooleanPropertyObject()));
	section.addProperty(new Property("Separate Specular", new BooleanPropertyObject()));
	section.addProperty(new Property("Two Sided Lighting", new BooleanPropertyObject()));
	section.addProperty(new Property("Mask Ambient", new BooleanPropertyObject()));
	section.addProperty(new Property("Mask Global Ambient", new BooleanPropertyObject()));
	section.addProperty(new Property("Mask Diffuse", new BooleanPropertyObject()));
	section.addProperty(new Property("Mask Specular", new BooleanPropertyObject()));

	section.setState(PropertySectionState.EXPANDED);

	model.addPropertySection(0, section);
    }

    /**
     * 
     * @param table
     * @param object
     */
    @Override
    protected void updateListeners(final RenderState renderstate) {

	super.updateListeners(renderstate);

	if(!(renderstate instanceof LightState))
	    return;

	final LightState state = (LightState) renderstate;

	ColorRGBAPropertyObject globalAmbient = (ColorRGBAPropertyObject) model.getPropertySection("Light State").getProperty("Global Ambient")
		.getPropertyObject();

	globalAmbient.SetListener(new I_ColorRGBAPropertyObjectListener() {

	    public ColorRGBA readValue() {

		return state.getGlobalAmbient();
	    }

	    public void saveValue(ColorRGBA value) {

		state.setGlobalAmbient(value);
	    }
	});

	BooleanPropertyObject localViewer = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Local Viewer")
		.getPropertyObject();

	localViewer.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return state.getLocalViewer();
	    }

	    public void saveValue(boolean value) {

		state.setLocalViewer(value);
	    }
	});

	BooleanPropertyObject separateSpecular = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Separate Specular")
		.getPropertyObject();

	separateSpecular.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return state.getSeparateSpecular();
	    }

	    public void saveValue(boolean value) {

		state.setSeparateSpecular(value);
	    }
	});

	BooleanPropertyObject twoSided = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Two Sided Lighting")
		.getPropertyObject();

	twoSided.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return state.getTwoSidedLighting();
	    }

	    public void saveValue(boolean value) {

		state.setTwoSidedLighting(value);
	    }
	});

	BooleanPropertyObject maskAmbient = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Mask Ambient")
		.getPropertyObject();

	maskAmbient.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (state.getLightMask() & LightState.MASK_AMBIENT) != 0;
	    }

	    public void saveValue(boolean value) {

		int mask = state.getLightMask();

		if(value)
		    mask |= LightState.MASK_AMBIENT;
		else
		    mask &= ~LightState.MASK_AMBIENT;

		state.setLightMask(mask);
	    }
	});

	BooleanPropertyObject maskGlobalAmbient = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Mask Global Ambient")
		.getPropertyObject();

	maskGlobalAmbient.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (state.getLightMask() & LightState.MASK_GLOBALAMBIENT) != 0;
	    }

	    public void saveValue(boolean value) {

		int mask = state.getLightMask();

		if(value)
		    mask |= LightState.MASK_GLOBALAMBIENT;
		else
		    mask &= ~LightState.MASK_GLOBALAMBIENT;

		state.setLightMask(mask);
	    }
	});

	BooleanPropertyObject maskDiffuse = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Mask Diffuse")
		.getPropertyObject();

	maskDiffuse.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (state.getLightMask() & LightState.MASK_DIFFUSE) != 0;
	    }

	    public void saveValue(boolean value) {

		int mask = state.getLightMask();

		if(value)
		    mask |= LightState.MASK_DIFFUSE;
		else
		    mask &= ~LightState.MASK_DIFFUSE;

		state.setLightMask(mask);
	    }
	});

	BooleanPropertyObject maskSpecular = (BooleanPropertyObject) model.getPropertySection("Light State").getProperty("Mask Specular")
		.getPropertyObject();

	maskSpecular.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (state.getLightMask() & LightState.MASK_SPECULAR) != 0;
	    }

	    public void saveValue(boolean value) {

		int mask = state.getLightMask();

		if(value)
		    mask |= LightState.MASK_SPECULAR;
		else
		    mask &= ~LightState.MASK_SPECULAR;

		state.setLightMask(mask);
	    }
	});

	for(int index = 0; index < state.getQuantity(); index++) {

	    final Light light = state.get(index);

	    if(light == null)
		continue;

	    PropertySection section = new PropertySection("Light: " + light.getType());

	    BooleanPropertyObject enabled = new BooleanPropertyObject();
	    section.addProperty(new Property("Enabled", enabled));

	    enabled.SetListener(new I_BooleanPropertyObjectListener() {

		public boolean readValue() {

		    return light.isEnabled();
		}

		public void saveValue(boolean value) {

		    light.setEnabled(value);
		}
	    });

	    if(light instanceof DirectionalLight) {

		Vector3fPropertyObject direction = new Vector3fPropertyObject();
		section.addProperty(new Property("Direction", direction));

		direction.SetListener(new I_Vector3fPropertyObjectListener() {

		    public Vector3f readValue() {

			return ((DirectionalLight) light).getDirection();
		    }

		    public void saveValue(Vector3f value) {

			((DirectionalLight) light).setDirection(value);
		    }
		});
	    }
	    else if(light instanceof PointLight) {

		Vector3fPropertyObject location = new Vector3fPropertyObject();
		section.addProperty(new Property("Location", location));

		location.SetListener(new I_Vector3fPropertyObjectListener() {

		    public Vector3f readValue() {

			return ((PointLight) light).getLocation();
		    }

		    public void saveValue(Vector3f value) {

			((PointLight) light).setLocation(value);
		    }
		});

		if(light instanceof SpotLight) {

		    Vector3fPropertyObject direction = new Vector3fPropertyObject();
		    section.addProperty(new Property("Direction", direction));

		    direction.SetListener(new I_Vector3fPropertyObjectListener() {

			public Vector3f readValue() {

			    return ((SpotLight) light).getDirection();
			}

			public void saveValue(Vector3f value) {

			    ((SpotLight) light).setDirection(value);
			}
		    });

		    FloatPropertyObject angle = new FloatPropertyObject();
		    section.addProperty(new Property("Angle", angle));

		    angle.SetListener(new I_FloatPropertyObjectListener() {

			public float readValue() {

			    return ((SpotLight) light).getAngle();
			}

			public void saveValue(float value) {

			    ((SpotLight) light).setAngle(value);
			}
		    });

		    FloatPropertyObject exponent = new FloatPropertyObject();
		    section.addProperty(new Property("Exponent", exponent));

		    exponent.SetListener(new I_FloatPropertyObjectListener() {

			public float readValue() {

			    return ((SpotLight) light).getExponent();
			}

			public void saveValue(float value) {

			    ((SpotLight) light).setExponent(value);
			}
		    });
		}
	    }

	    ColorRGBAPropertyObject ambient = new ColorRGBAPropertyObject();
	    section.addProperty(new Property("Ambient", ambient));

	    ambient.SetListener(new I_ColorRGBAPropertyObjectListener() {

		public ColorRGBA readValue() {

		    return light.getAmbient();
		}

		public void saveValue(ColorRGBA value) {

		    light.setAmbient(value);
		}
	    });

	    ColorRGBAPropertyObject diffuse = new ColorRGBAPropertyObject();
	    section.addProperty(new Property("Diffuse", diffuse));

	    diffuse.SetListener(new I_ColorRGBAPropertyObjectListener() {

		public ColorRGBA readValue() {

		    return light.getDiffuse();
		}

		public void saveValue(ColorRGBA value) {

		    light.setDiffuse(value);
		}
	    });

	    ColorRGBAPropertyObject specular = new ColorRGBAPropertyObject();
	    section.addProperty(new Property("Specular", specular));

	    specular.SetListener(new I_ColorRGBAPropertyObjectListener() {

		public ColorRGBA readValue() {

		    return light.getSpecular();
		}

		public void saveValue(ColorRGBA value) {

		    light.setSpecular(value);
		}
	    });

	    FloatPropertyObject constant = new FloatPropertyObject();
	    section.addProperty(new Property("Constant", constant));

	    constant.SetListener(new I_FloatPropertyObjectListener() {

		public float readValue() {

		    return light.getConstant();
		}

		public void saveValue(float value) {

		    light.setConstant(value);
		}
	    });

	    FloatPropertyObject linear = new FloatPropertyObject();
	    section.addProperty(new Property("Linear", linear));

	    linear.SetListener(new I_FloatPropertyObjectListener() {

		public float readValue() {

		    return light.getLinear();
		}

		public void saveValue(float value) {

		    light.setLinear(value);
		}
	    });

	    FloatPropertyObject quadratic = new FloatPropertyObject();
	    section.addProperty(new Property("Quadratic", quadratic));

	    quadratic.SetListener(new I_FloatPropertyObjectListener() {

		public float readValue() {

		    return light.getQuadratic();
		}

		public void saveValue(float value) {

		    light.setQuadratic(value);
		}
	    });

	    BooleanPropertyObject lightMaskAmbient = new BooleanPropertyObject();
	    section.addProperty(new Property("Mask Ambient", lightMaskAmbient));

	    lightMaskAmbient.SetListener(new I_BooleanPropertyObjectListener() {

		public boolean readValue() {

		    return (light.getLightMask() & LightState.MASK_AMBIENT) != 0;
		}

		public void saveValue(boolean value) {

		    int mask = light.getLightMask();

		    if(value)
			mask |= LightState.MASK_AMBIENT;
		    else
			mask &= ~LightState.MASK_AMBIENT;

		    light.setLightMask(mask);
		}
	    });

	    BooleanPropertyObject lightMaskGlobalAmbient = new BooleanPropertyObject();
	    section.addProperty(new Property("Mask Global Ambient", lightMaskGlobalAmbient));

	    lightMaskGlobalAmbient.SetListener(new I_BooleanPropertyObjectListener() {

		public boolean readValue() {

		    return (light.getLightMask() & LightState.MASK_GLOBALAMBIENT) != 0;
		}

		public void saveValue(boolean value) {

		    int mask = light.getLightMask();

		    if(value)
			mask |= LightState.MASK_GLOBALAMBIENT;
		    else
			mask &= ~LightState.MASK_GLOBALAMBIENT;

		    light.setLightMask(mask);
		}
	    });

	    BooleanPropertyObject lightMaskDiffuse = new BooleanPropertyObject();
	    section.addProperty(new Property("Mask Diffuse", lightMaskDiffuse));

	    lightMaskDiffuse.SetListener(new I_BooleanPropertyObjectListener() {

		public boolean readValue() {

		    return (light.getLightMask() & LightState.MASK_DIFFUSE) != 0;
		}

		public void saveValue(boolean value) {

		    int mask = light.getLightMask();

		    if(value)
			mask |= LightState.MASK_DIFFUSE;
		    else
			mask &= ~LightState.MASK_DIFFUSE;

		    light.setLightMask(mask);
		}
	    });

	    BooleanPropertyObject lightMaskSpecular = new BooleanPropertyObject();
	    section.addProperty(new Property("Mask Specular", lightMaskSpecular));

	    lightMaskSpecular.SetListener(new I_BooleanPropertyObjectListener() {

		public boolean readValue() {

		    return (light.getLightMask() & LightState.MASK_SPECULAR) != 0;
		}

		public void saveValue(boolean value) {

		    int mask = light.getLightMask();

		    if(value)
			mask |= LightState.MASK_SPECULAR;
		    else
			mask &= ~LightState.MASK_SPECULAR;

		    light.setLightMask(mask);
		}
	    });

	    section.setState(PropertySectionState.EXPANDED);

	    model.addPropertySection(0, section);
	}
    }
}
